package com.atguigu.crowd.mvc.handler;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.fasterxml.jackson.databind.node.BigIntegerNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import com.atguigu.crowd.entity.Menu;
import com.atguigu.crowd.service.api.MenuService;
import com.atguigu.crowd.util.ResultEntity;

//@Controller

@RestController
public class MenuHandler {

	@Autowired 
	private MenuService menuService;

	/**
	 * 删除子节点3:前端请求传Json对象（前端不要用contentType说明请求体内容，也不用转成Json对象的字符串）
	 * 则后端使用后端用@RequestParam接收参数
	 * 比如我这里是 @RequestParam("id") Integer id 则前端必须是对应的，要有这个参数，不要转成Json对象的字符串
	 * 比如我这里前端必须是 var requestBody = {"id":window.id,"name":name};
	 */
	//@ResponseBody
	@RequestMapping("/menu/remove3.json")
	public ResultEntity<String> removeMenu3(@RequestParam("id") Integer id) {

		int result = menuService.removeMenu(id);

		//预留个可能会出现的bug  因为我们没有判断 result 是否大于0 就是保存成功了没有

		return ResultEntity.successWithoutData();
	}

	/**
	 * 删除子节点2:前端请求传Json对象的字符串（前端必须要用contentType说明请求体内容）
	 * 则后端使用@RequestBody，参数类型有要求，数组或者对象数组，或者说 必须跟前端传进来的是对应的，
	 * 比如我这里是 @RequestBody List<Integer> ids 则前端必须是传进来的也是数组，只是转成了Json对象的字符串
	 * 前端必须是 var requestBody = JSON.stringify([1,2,3,4,5]) 这种，即原代码为var requestBody = JSON.stringify([window.id])
	 */
	//@ResponseBody
	@RequestMapping("/menu/remove2.json")
	public ResultEntity<String> removeMenu2(@RequestBody List<Integer> ids ) {

		for (Integer id:ids) {
			int result = menuService.removeMenu(id);
		}

		//预留个可能会出现的bug  因为我们没有判断 result 是否大于0 就是保存成功了没有

		return ResultEntity.successWithoutData();
	}
	/**
	 * 删除子节点
	 * 前端请求传Json对象的字符串（前端必须要用contentType说明请求体内容）
	 * 则后端使用@RequestBody，参数类型有要求，必须是【对象】或者数组，或者说，必须跟前端传进来的是对应的，
	 * 比如我这里是 @RequestBody Menu menu 的话 则前端必须是传进来的也是Menu对象，只是转成了Json对象的字符串
	 * 实例：我们的前端必须是 var requestBody = JSON.stringify({"id":window.id,"name":name});它里面有Menu对象的属性
	 */
	//@ResponseBody
	@RequestMapping("/menu/remove.json")
	public ResultEntity<String> removeMenu(@RequestBody Menu menu ) {

		 int result = menuService.removeMenu(menu.getId());

		//预留个可能会出现的bug  因为我们没有判断 result 是否大于0 就是保存成功了没有

		return ResultEntity.successWithoutData();
	}

    /**
     * 修改子节点
     */
    //@ResponseBody
    @RequestMapping("/menu/update.json")
    public ResultEntity<String> updateMenu(Menu menu) {

	    int result = menuService.updateMenu(menu);

	    //预留个可能会出现的bug  因为我们没有判断 result 是否大于0 就是保存成功了没有

	    return ResultEntity.successWithoutData();
    }

	/**
	 * 添加子节点
	 */
	//@ResponseBody
	@RequestMapping("/menu/save.json")
	public ResultEntity<String> saveMenu(Menu menu) throws Exception{

		//测试异步的问题，测试完请注释
		//Thread.sleep(5000);

		int result = menuService.saveMenu(menu);

		//预留个可能会出现的bug  因为我们没有判断 result 是否大于0 就是保存成功了没有

		return ResultEntity.successWithoutData();
	}
	
	/**
	 * 父节点和子节点的关系建立：推荐，这个算法时间复杂度最小，循环不嵌套，推荐
	 * @return
	 */
	//@ResponseBody
	@RequestMapping("/menu/get/whole/treeNew.ht")
	public ResultEntity<Menu> getWholeTreeNew(){
		//1、查询出全部的Menu对象
		List<Menu>menuList=menuService.getAll();
		
		//2、声明一个变量用来存储找到的根节点
		Menu menuRoot=null;
		
		//3、创建Map对象用来存储id和Menu对象的对应关系 便于查询父节点
		Map<Integer,Menu>menuMap=new HashMap<Integer,Menu>();
		
		//4、遍历menuList填充menuMap —— 管它的，先全部填充到键值对里面去再说
		for (Menu menu : menuList) {
			
			Integer id=menu.getId();
			
			menuMap.put(id, menu);
		}
		//5、再次遍历 menuList 查找根节点，组装父子节点
		for (Menu menu : menuList) {
			
			//6、获取当前menu对象的pid属性值
			Integer pid=menu.getPid();
			
			//7、如果pid为null，判断为根节点
			if (pid==null) {
				menuRoot=menu;
				//如果当前节点是根节点，那么肯定没有父节点了，则不必继续执行
				continue;
			}
			
			//9、如果pid不为null，则继续往下走，说明当前节点有父节点，那么可以根据pid到menuMap中农查找对应的Menu对象
			Menu father=menuMap.get(pid);
			
			//10、将当前节点存入父节点的children集合
			father.getChildren().add(menu);
		}
		//11、经过上面的运算，根节点包含了整个树形结构
		return ResultEntity.successWithData(menuRoot);
	}
	/**
	 * 父节点和子节点的关系建立（旧的），这个算法，时间复杂度过大
	 * @return
	 */
	//@ResponseBody
	@RequestMapping("/menu/get/whole/tree0ld.ht")
	public ResultEntity<Menu>getWholeTreeOld(){
		
		//1、查询出全部的Menu对象
		List<Menu>menuList=menuService.getAll();
		
		//2、声明一个变量用来存储找到的根节点
		Menu menuRoot=null;
		
		//3、遍历menuList 
		for (Menu menu : menuList) {
			//4、获取当前menu对象的pid的属性值
			Integer pid=menu.getPid();
			
			//5、检查pid是否为null或者0，pid是null或者0就是根节点，这个要根据具体情况来，具体情况具体分析
			if(pid==null) {
				
				//6、把当前正在遍历的这个menu对象赋值给menuRoot
				menuRoot=menu;
				
				//7、找到父节点了，停止本次循环,继续执行下一次循环,这是一个优化，因为 父节点可以有多个子节点，子节点只能有1个父节点  所以不必再往下找了
				continue;
			}
			//8、如果pid不为null，则走下面的代码， 说明当前节点有父节点，，找到父节点就可以直接进行组装，建立父子关系
			for (Menu maybeFather : menuList) {
				
				//9、获取 maybeFather的id属性
				Integer id=maybeFather.getId();
				
				//10、将子节点的pid和疑似父节点的id进行比较：如果pid = id
				if (Objects.equals(pid, id)) {
					
					//11、将子节点存入父节点的children集合
					maybeFather.getChildren().add(menu);
					
					//12、找到即可停止循环/完全跳出这个for循环
					break;
				}
			}
		}
		//13、将组装的树形结构（也就是根节点对象）返回给浏览器
		return ResultEntity.successWithData(menuRoot);
	}
}
